using Godot;
using System;
using Godot.Collections;
using CurrentGame.Utils.Interpolation;

namespace CurrentGame.GUI;


public partial class DialogueBox : Control
{
	[Signal]
	public delegate void DialogueFinishedEventHandler();

	[Export]
	public bool Opened
	{
		get => _opened;
		set
		{
            _opened = value;
            if (_ready)
			{
				if (_opened) OpenDialogueBox();
				else CloseDialogueBox();
			}
		}
	}
	private bool _opened = false;
	[Export]
	public Array<string> ShowContent
	{
		get => _showContent;
		set
		{
			_showContent = value;
			_currentTextIter = 0;
		}
	}
	private Array<string> _showContent = [];

	[ExportGroup("Interpolation")]
	[Export]
	public float InterpolationWeight
	{
		get => _interpolationWeight;
		set
		{
			_interpolationWeight = value;
			_interpolation.Weight = value;
        }
	}
	private float _interpolationWeight = 0.2f;

	// Text show interpolation
	private LerpInterpolation _interpolation;
	private bool _showState = false, _ready = false;
	private int _currentTextIter = 0;

	// Child node reference
	private Label _mainText;
	private DialogueBoxAnimTree _animTree;


	public DialogueBox()
	{
        _interpolation = new(0.01f, new Vector3(0.001f, -1, -1))
        {
            Weight = _interpolationWeight,
            Value = 1.0f
        };
        _interpolation.Teleport();
		_interpolation.ReachStableValue += InterpolationStable;
	}

	// Called when the node enters the scene tree for the first time.
	public override void _Ready()
	{
		_mainText = GetNode<Label>("VBoxContainer/MainText/Text");
		_animTree = GetNode<DialogueBoxAnimTree>("AnimationPlayer/AnimationTree");
		_animTree.Opened = _opened;     // Sync
		if (_opened) OpenDialogueBox();

		_ready = true;
	}

	// Called every frame. 'delta' is the elapsed time since the previous frame.
	public override void _Process(double delta)
	{
		if (_interpolation.Process(delta))
		{
			_mainText.Modulate = new(1.0f, 1.0f, 1.0f, _interpolation.Value);
		}
	}

    public override void _GuiInput(InputEvent @event)
    {
        if (_showState && Input.IsActionJustPressed("dialogue_accept"))
		{
			if (_currentTextIter < _showContent.Count - 1)
			{
				_showState = false;
				_interpolation.Value = 0.0f;
				_currentTextIter += 1;		// next text
			}
			else
			{
				// final sentence
				CloseDialogueBox();
			}
		}
		AcceptEvent();
    }

    public void ReGrabFocus()
    {
        if (_opened) CallDeferred(MethodName.GrabFocus);
    }

    // private functions
    private void UpdateCurrentDisplay()
	{
		Mathf.Clamp(_currentTextIter, 0, _showContent.Count - 1);
		_mainText.Text = _showContent[_currentTextIter];
	}

	private void OpenDialogueBox()
	{
        _currentTextIter = 0;
        UpdateCurrentDisplay();
		_showState = true;
        CallDeferred(MethodName.GrabFocus);

		_animTree.Opened = true;
	}

	private void CloseDialogueBox()
	{
		_opened = false;
		_showState = false;
		ReleaseFocus();

		_animTree.Opened = false;
	}

	private void InterpolationStable(float v, Vector2 v2, Vector3 v3)
	{
		if (v < 0.5f)
		{
			// hide
			UpdateCurrentDisplay();			// change text
			_interpolation.Value = 1.0f;	// show text
		}
		else
		{
			// show
			_showState = true;
		}
	}


	// GODOT Signals

	private void Signal_DialogueBoxAnimFinished(StringName animName)
	{
		var animation = animName.ToString();
		if (animation == "leave")
		{
			EmitSignal(SignalName.DialogueFinished);
		}
	}
}
